package com.lan.model;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class Clazz {

    private Class<?> clazz;

    private boolean isStatic = false;

    private Object value;

    private final Map<String, Method> methodMap = new HashMap<>();

    public Clazz(Class<?> clazz) {
        this.clazz = clazz;
    }

    public Object newInstance() throws IllegalAccessException, InstantiationException {
        return clazz.newInstance();
    }

    public Object newInstanceStatic() throws IllegalAccessException, InstantiationException {
        if (value == null) {
            value = clazz.newInstance();
        }
        return value;
    }


    public Object invoke0(Object o, String methodName, Object[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class<?>[] parameterTypes = new Class<?>[args.length];
        StringBuilder sb = new StringBuilder(methodName);
        for (int i = 0; i < args.length; i++) {
            parameterTypes[i] = args[i].getClass();
            sb.append("_").append(parameterTypes[i].getSimpleName());
        }
        String cacheKey = sb.toString();
        Method method = methodMap.get(cacheKey);
        if (method == null) {
            method = o.getClass().getMethod(methodName, parameterTypes);
            methodMap.put(cacheKey, method);
        }
        return method.invoke(o, args);
    }


    public Object getVar(Object o, String prop) throws NoSuchFieldException, IllegalAccessException {
        Field field = o.getClass().getDeclaredField(prop);
        return field.get(o);
    }


    public Object invoke(String methodName, Object[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        newInstanceStatic();
        Class<?>[] parameterTypes = null;
        StringBuilder sb = new StringBuilder(methodName);
        if (args != null) {
            parameterTypes = new Class<?>[args.length];
            for (int i = 0; i < args.length; i++) {
                parameterTypes[i] = args[i].getClass();
                sb.append("_").append(parameterTypes[i].getSimpleName());
            }
        }
        String cacheKey = sb.toString();
        Method method = methodMap.get(cacheKey);
        if (method == null) {
            method = value.getClass().getMethod(methodName, parameterTypes);
            methodMap.put(cacheKey, method);
        }
        return method.invoke(null, args);
    }


    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }
}
